package javamem;

import com.sun.management.OperatingSystemMXBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.lang.management.ManagementFactory;
import java.text.NumberFormat;
import java.util.Scanner;

public class MemTool {

    private static Logger logger = LoggerFactory.getLogger(MemTool.class);

    /*
    -Dcom.sun.management.jmxremote.port=8888 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
     */
    public static MemInfo getPermGenInfo(String ip, int port) {
        JMXConnector connector = null;
        try {
            String jmxURL = "service:jmx:rmi:///jndi/rmi://" + ip + ":" + port + "/jmxrmi";
            JMXServiceURL serviceURL = new JMXServiceURL(jmxURL);

            connector = JMXConnectorFactory.connect(serviceURL);
            MBeanServerConnection mbsc = connector.getMBeanServerConnection();

            ObjectName PermGen = new ObjectName("java.lang:type=MemoryPool,name=Perm Gen");
            CompositeDataSupport dataSupport;
            try {
                dataSupport = (CompositeDataSupport) mbsc.getAttribute(PermGen, "Usage");
            } catch (javax.management.InstanceNotFoundException ex) {
                PermGen = new ObjectName("java.lang:type=MemoryPool,name=PS Perm Gen");
                dataSupport = (CompositeDataSupport) mbsc.getAttribute(PermGen, "Usage");
            }

            //long committed = (Long)dataSupport.get("committed");
            long init = (Long)dataSupport.get("init");
            long max = (Long)dataSupport.get("max");
            long used = (Long)dataSupport.get("used");

            return new MemInfo(init, max, used);
        } catch (Exception ex) {
            logger.error("getPermGen error", ex);
            return null;
        } finally {
            if(connector != null) {
                try {
                    connector.close();
                } catch (Exception ex) {
                    // do nothing
                }
            }
        }
    }

    public static MemInfo getSystemMem() {
        OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        long totalMem = operatingSystemMXBean.getTotalPhysicalMemorySize();
        long freeMem = operatingSystemMXBean.getFreePhysicalMemorySize();
        long usedMem = totalMem - freeMem;

        return new MemInfo(0, totalMem, usedMem);
    }

    public static double getUsedRate(MemInfo memInfo) {
        double max = memInfo.getMax();
        double used = memInfo.getUsed();

        double usedRate = ((used * 1.0) / max) * 100;

        NumberFormat nb = NumberFormat.getNumberInstance();
        nb.setMaximumFractionDigits(2);

        return Double.parseDouble(nb.format(usedRate));
    }

    public static String byte2MB(double b) {
        double b2M = 1024 * 1024;
        NumberFormat nb = NumberFormat.getNumberInstance();
        nb.setMaximumFractionDigits(1);

        return nb.format(b/b2M) + "MB";
    }

    public static void showMemInfo() {
        Config config = Config.getInstance();
        String ip = config.getString("jmx.ip");
        int port = config.getInt("jmx.port");
        double sysWarnLevel = config.getDouble("system.mem.warn.level");
        double permWarnLevel = config.getDouble("java.perm.warn.level");

        MemInfo sysMemInfo = MemTool.getSystemMem();
        logger.info("---------System Memory Info--------------");
        logger.info("max=" + byte2MB(sysMemInfo.getMax()));
        logger.info("used=" + byte2MB(sysMemInfo.getUsed()));
        double usedRate = getUsedRate(sysMemInfo);
        logger.info("usedRate=" + usedRate + "%");
        if(usedRate > sysWarnLevel) {
            logger.warn("<<< System Memory Warning !!! >>>");
        }

        MemInfo permGenInfo = MemTool.getPermGenInfo(ip, port);
        logger.info("---------Java PermGen Info---------------");
        logger.info("init=" + byte2MB(permGenInfo.getInit()));
        logger.info("max=" + byte2MB(permGenInfo.getMax()));
        logger.info("used=" + byte2MB(permGenInfo.getUsed()));
        usedRate = getUsedRate(permGenInfo);
        logger.info("usedRate=" + usedRate + "%");
        if(usedRate > permWarnLevel) {
            logger.warn("<<< Java PermGen Warning !!! >>>");
        }

        Scanner scanner = new Scanner(System.in);
        System.out.print("press any key to quit >");
        scanner.nextLine();

        System.exit(0);
    }

    public static void main(String[] args) {
        MemTool.showMemInfo();
    }

}
